from flask import Flask, render_template, request, jsonify
from flask_wtf.csrf import CSRFError
import os
import click

from app.blueprints.poly import poly_bp
from app.blueprints.auth import auth_bp
from app.blueprints.admin import admin_bp
from app.blueprints.user import user_bp
from app.apis.v1 import api_v1
from app.models import User, Crawler, Record, Subscribe, Category, Role
from app.settings import config
from app.extensions import db, login_manager, csrf, migrate, scheduler

basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))


def create_app(config_name=None):
    if config_name is None:
        config_name = os.getenv('FLASK_CONFIG', 'development')
    app = Flask('polymer')
    app.config.from_object(config[config_name])

    register_blueprints(app)
    register_extensions(app)
    register_errors(app)
    register_shell_context(app)
    register_template_context(app)
    register_commands(app)
    return app


def register_blueprints(app):
    app.register_blueprint(poly_bp)
    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(user_bp, url_prefix='/user')
    app.register_blueprint(admin_bp, url_prefix='/admin')
    app.register_blueprint(api_v1, url_prefix='/api/v1')


def register_extensions(app):
    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)
    csrf.exempt(api_v1)
    migrate.init_app(app, db)
    scheduler.init_app(app)
    scheduler.start()


def register_shell_context(app):
    @app.shell_context_processor
    def make_shell_context():
        return dict(db=db, User=User, Crawler=Crawler, Record=Record, Subscribe=Subscribe, scheduler=scheduler)


def register_errors(app):
    @app.errorhandler(400)
    def bad_request(e):
        return render_template('errors/400.html'), 400

    @app.errorhandler(404)
    def page_not_found(e):
        if request.accept_mimetypes.accept_json \
                and not request.accept_mimetypes.accept_html or request.path.startswith('/api'):
            response = jsonify(code=404, message='The resource is not existed!')
            response.status_code = 404
            return response
        return render_template('errors/404.html'), 404

    @app.errorhandler(500)
    def internal_server_error(e):
        return render_template('errors/500.html'), 500

    @app.errorhandler(CSRFError)
    def handle_csrf_error(e):
        return render_template('errors/400.html', description=e.description), 400


def register_template_context(app):
    @app.context_processor
    def make_template_context():
        return dict()


def register_commands(app):
    @app.cli.command()
    @click.option('--drop', is_flag=True, help='重建数据库')
    def initdb(drop):
        if drop:
            click.confirm('这个操作会删除你的数据库，确定吗？', abort=True)
            db.drop_all()
            click.echo('删除数据表')
        db.create_all()
        category = Category(title='default')
        db.session.add(category)
        db.session.commit()
        Role.init_role()
        click.echo('初始化数据库')
